package com.autumn.redis;

import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.autumn.util.DateUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.Time;
import com.autumn.util.TimeSpan;
import com.autumn.util.json.JsonUtils;
import com.autumn.util.tuple.TupleTwo;

/**
 * Redis 模板
 * 
 * @author 老码农
 *
 *         2017-12-12 21:13:19
 */
public class AutumnRedisTemplate extends StringRedisTemplate {

	/**
	 * 
	 */
	public final static RedisSerializer<String> STRING_SERIALIZER = new StringRedisSerializer(StandardCharsets.UTF_8);

	/**
	 * 
	 */
	public AutumnRedisTemplate() {
		super();
	}

	/**
	 * 
	 * @param connectionFactory
	 */
	public AutumnRedisTemplate(RedisConnectionFactory connectionFactory) {
		super(connectionFactory);
	}

	/**
	 * 设置 String 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, String value) {
		new AutumnValueOperations<String>(this).set(key, value);
	}

	/**
	 * 设置 String 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, String value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<String>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Byte 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, byte value) {
		new AutumnValueOperations<Byte>(this).set(key, value);
	}

	/**
	 * 设置 Byte 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, byte value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Byte>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Short 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, short value) {
		new AutumnValueOperations<Short>(this).set(key, value);
	}

	/**
	 * 设置 Short 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, short value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Short>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Integer 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, int value) {
		new AutumnValueOperations<Integer>(this).set(key, value);
	}

	/**
	 * 设置 Integer 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, int value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Integer>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Long 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, long value) {
		new AutumnValueOperations<Long>(this).set(key, value);
	}

	/**
	 * 设置 Long 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, long value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Long>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Float 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, float value) {
		new AutumnValueOperations<Float>(this).set(key, value);
	}

	/**
	 * 设置 Float 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, float value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Float>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 double 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, double value) {
		new AutumnValueOperations<Double>(this).set(key, value);
	}

	/**
	 * 设置 double 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, double value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Double>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 BigDecimal 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, BigDecimal value) {
		new AutumnValueOperations<BigDecimal>(this).set(key, value);
	}

	/**
	 * 设置 BigDecimal 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, BigDecimal value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<BigDecimal>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Time 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, Time value) {
		new AutumnValueOperations<Time>(this).set(key, value);
	}

	/**
	 * 设置 Time 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, Time value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<Time>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 TimeSpan 值
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, TimeSpan value) {
		new AutumnValueOperations<TimeSpan>(this).set(key, value);
	}

	/**
	 * 设置 TimeSpan 值
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, TimeSpan value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<TimeSpan>(this).set(key, value, timeout, unit);
	}

	/**
	 * 设置 Date 值(精确到秒)
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, Date value) {
		String str;
		if (value == null) {
			str = null;
		} else {
			str = DateUtils.dateFormat(value);
		}
		new AutumnValueOperations<String>(this).set(key, str);
	}

	/**
	 * 设置 Date 值(精确到秒)
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, Date value, long timeout, TimeUnit unit) {
		String str;
		if (value == null) {
			str = null;
		} else {
			str = DateUtils.dateFormat(value);
		}
		new AutumnValueOperations<String>(this).set(key, str, timeout, unit);
	}

	private String getObjectString(Object value) {
		if (value == null) {
			return null;
		} else {
			if (value instanceof String) {
				return value.toString();
			} else {
				return JsonUtils.toJSONString(value);
			}
		}
	}

	/**
	 * 设置对象值(将全部按照Json格式)
	 * 
	 * @param key
	 *            键值
	 * @param value
	 *            值
	 */
	public void set(String key, Object value) {
		new AutumnValueOperations<String>(this).set(key, getObjectString(value));
	}

	/**
	 * 设置对象值(将全部按照Json格式)
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            值
	 * @param timeout
	 *            超时时间
	 * @param unit
	 *            时间单位
	 */
	public void set(String key, Object value, long timeout, TimeUnit unit) {
		new AutumnValueOperations<String>(this).set(key, getObjectString(value), timeout, unit);
	}

	/**
	 * 获取 String 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public String getString(String key) {
		return new AutumnValueOperations<String>(this).get(key, (value) -> {
			return value;
		});
	}

	/**
	 * 获取 String 值并删除
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public String getStringByDelete(String key) {
		return new AutumnValueOperations<String>(this).getByDelete(key, (value) -> {
			return value;
		});
	}

	/**
	 * 获取 Byte 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Byte getByte(String key) {
		return new AutumnValueOperations<Byte>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Byte.parseByte(value);
		});
	}

	/**
	 * 获取 Short 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Short getShort(String key) {
		return new AutumnValueOperations<Short>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Short.parseShort(value);
		});
	}

	/**
	 * 获取 Integer 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Integer getInteger(String key) {
		return new AutumnValueOperations<Integer>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Integer.parseInt(value);
		});
	}

	/**
	 * 获取 Long 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Long getLong(String key) {
		return new AutumnValueOperations<Long>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Long.parseLong(value);
		});
	}

	/**
	 * 获取 Float 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Float getFloat(String key) {
		return new AutumnValueOperations<Float>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Float.parseFloat(value);
		});
	}

	/**
	 * 获取 Double 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Double getDouble(String key) {
		return new AutumnValueOperations<Double>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Double.parseDouble(value);
		});
	}

	/**
	 * 获取 BigDecimal 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public BigDecimal getBigDecimal(String key) {
		return new AutumnValueOperations<BigDecimal>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return new BigDecimal(value);
		});
	}

	/**
	 * 获取 Time 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Time getTime(String key) {
		return new AutumnValueOperations<Time>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return Time.parse(value);
		});
	}

	/**
	 * 获取 TimeSpan 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public TimeSpan getTimeSpan(String key) {
		return new AutumnValueOperations<TimeSpan>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return TimeSpan.parse(value);
		});
	}

	/**
	 * 获取 Date 值
	 * 
	 * @param key
	 *            键
	 * @return
	 */
	public Date getDate(String key) {
		return new AutumnValueOperations<Date>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return DateUtils.parseDate(value);
		});
	}

	/**
	 * 获取值(全部采用Json解析)
	 * 
	 * @param key
	 *            键
	 * @param type
	 *            类型
	 * @return
	 */
	public <T> T get(String key, Class<T> type) {
		return new AutumnValueOperations<T>(this).get(key, (value) -> {
			if (StringUtils.isNullOrBlank(value)) {
				return null;
			}
			return JsonUtils.parseObject(value, type);
		});
	}

	/**
	 * 获取值并删除(全部采用Json解析)
	 * 
	 * @param key
	 *            键
	 * @param type
	 *            类型
	 * @return
	 */
	public <T> T getByDelete(String key, Class<T> type) {
		return new AutumnValueOperations<T>(this).getByDelete(key, (value) -> {
			if (value == null || StringUtils.isNullOrBlank(value)) {
				return null;
			}
			return JsonUtils.parseObject(value, type);
		});
	}

	/**
	 * 获取值(全部采用Json解析)
	 * 
	 * @param key
	 *            键
	 * @param type
	 *            类型
	 * @return
	 */
	public Object get(String key, Type type) {
		return new AutumnValueOperations<Object>(this).get(key, (value) -> {
			if (value == null) {
				return null;
			}
			return JsonUtils.parseObject(value, type);
		});
	}

	/**
	 * 原子递增(++)
	 * 
	 * @param key
	 *            键
	 * 
	 * @return
	 */
	public Long incr(String key) {
		return new AutumnValueOperations<Long>(this).incr(key);
	}

	/**
	 * 原子递增(+=delta)
	 * 
	 * @param key
	 *            键
	 * @param delta
	 *            步长
	 * @return
	 */
	public Long incrBy(String key, long delta) {
		return new AutumnValueOperations<Long>(this).incrBy(key, delta);
	}

	/**
	 * 原子递减(--)
	 * 
	 * @param key
	 *            键
	 * 
	 * @return
	 */
	public Long decr(String key) {
		return new AutumnValueOperations<Long>(this).decr(key);
	}

	/**
	 * 原子递减(-=delta)
	 * 
	 * @param key
	 *            键
	 * @param delta
	 *            步长
	 * @return
	 */
	public Long decrBy(String key, long delta) {
		return new AutumnValueOperations<Long>(this).decrBy(key, delta);
	}

	/**
	 * 条件原子递减(-=delta)
	 * 
	 * @param key
	 *            键
	 * @param delta
	 *            步长
	 * @param minValue
	 *            最小值
	 * @return
	 */
	public TupleTwo<Boolean, Long> decrByIf(String key, long delta, long minValue) {
		return new AutumnValueOperations<TupleTwo<Boolean, Long>>(this).decrByIf(key, delta, minValue);
	}

	/**
	 * 在原有的字符窜上追加字符窜
	 * 
	 * @param key
	 *            键
	 * @param value
	 *            追加的字符窜
	 * @return 返回新字符的总长度，若原 key 不存在则返回 null
	 */
	public Integer append(String key, String value) {
		return this.opsForValue().append(key, value);
	}

	/**
	 * 表达基于表达式匹配删除
	 * 
	 * @param keyExpression
	 *            键表达式
	 *            <p>
	 *            a* 表示a为开头的键
	 *            </p>
	 *            <p>
	 *            *a 表示以a为结束的键
	 *            </p>
	 * @return 返回成功删除的键数量
	 */
	public long deleteByMatches(String keyExpression) {
		return new AutumnValueOperations<Long>(this).deleteByMatches(keyExpression);
	}

}
